/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.awt; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.Vector; /** * A class that produces a Spin Button. * * <P> * <TABLE BORDER COLS=3 WIDTH=100%> * <TR><TH WIDTH=15%>Property<TH WIDTH=15%>Property Type<TH>Description * <TR><TD> Orientation <TD> boolean <TD> Orientation of SpinButton (Left-right or Up-down) * <TR><TD> Minimum <TD> int <TD> Minimum value. * <TR><TD> Maximum <TD> int <TD> Maximum value. * <TR><TD> Step <TD> int <TD> Step. * <TR><TD> Value <TD> int <TD> Current value. * <TR><TD> RepeatDelay <TD> int <TD> Delay time after press SpinButton [ms] * <TR><TD> RepeatRate <TD> int <TD> Repeat rate while holding PressButton [ms] * </TABLE> * * @version 3.06, November 17, 1997 * @author Petr Hamernik, Jan Jancura */ public class SpinButton extends Canvas { /** generated Serialized Version UID */ static final long serialVersionUID = -3525959415481788776L; /** Default orientation of SpinButton. Currently false (UP-DOWN). * @see #DEFAULT_ORIENTATION * @see #setOrientation * @see #getOrientation */ public static final boolean DEFAULT_ORIENTATION = false; /** Current orientation of SpinButton. * True = LEFT-RIGHT, False = UP-DOWN * @see #DEFAULT_ORIENTATION * @see #setOrientation * @see #getOrientation */ protected boolean orientation = DEFAULT_ORIENTATION; /** Current orientation of arrows of SpinButton. * True = LEFT-RIGHT, False = UP-DOWN * @see #DEFAULT_ORIENTATION * @see #setOrientation * @see #getOrientation */ protected boolean arrowsOrientation = DEFAULT_ORIENTATION; /** Default minimum. Currently 0. * @see #minimum * @see #setMinimum * @see #getMinimum */ public static final int DEFAULT_MINIMUM = 0; /** Minimum of the range of the SpinButton. * @see #DEFAULT_MINIMUM * @see #setMinimum * @see #getMinimum */ protected int minimum = DEFAULT_MINIMUM; /** Default maximum. Currently 100. * @see #maximum * @see #setMaximum * @see #getMaximum */ public static final int DEFAULT_MAXIMUM = 100; /** Maximum of the range of the SpinButton. * @see #DEFAULT_MAXIMUM * @see #setMaximum * @see #getMaximum */ protected int maximum = DEFAULT_MAXIMUM; /** Default step. Currently 1. * @see #step * @see #setStep * @see #getStep */ public static final int DEFAULT_STEP = 1; /** Step of the SpinButton. * @see #DEFAULT_STEP * @see #setStep * @see #getStep */ protected int step = DEFAULT_STEP; /** Value of the SpinButton. Default 0. * @see #setValue * @see #getValue */ protected int value = 0; /** Default value of repeatDelay. Currently 300 ms. * @see #setDelay * @see #getDelay * @see #repeatDelay */ public static final int DEFAULT_REPEAT_DELAY = 300; /** Adjusts the amount of time that elapses before a increment * (or decrement) begins repeating when you hold down a mouse * button. [ms] * @see #setDelay * @see #getDelay * @see #DEFAULT_REPEAT_DELAY */ protected int repeatDelay = DEFAULT_REPEAT_DELAY; /** Default value of repeatRate. Currently 70 ms. * @see #setRate * @see #getRate * @see #repeatRate */ public static final int DEFAULT_REPEAT_RATE = 70; /** Adjusts the speed at which a increment (or decrement) * repeats when you hold down a mouse button. [ms] * @see #setRate * @see #getRate * @see #DEFAULT_REPEAT_RATE */ protected int repeatRate = DEFAULT_REPEAT_RATE; /** Spin repeat thread. When the SpinButton is holded this thread * runs and regulary sends the events to SpinButton. */ protected RepeatThread rt = null; /** Flag if the SpinRepeatThread is currently running. */ protected boolean running = false; /** Flag if the SpinRepeatThread is currently running. */ protected boolean repeating = true; /** Helper constant */ private static final boolean SPIN_UP = true; /** Helper constant */ private static final boolean SPIN_DOWN = false; /** Current direction of the run of the SpinRepeatThread. */ protected boolean runningDir = SPIN_DOWN; protected boolean boundsIgnored = false; /** Property change listeners storage */ private PropertyChangeSupport valueSupport = new PropertyChangeSupport(this); /** SpinButton change listeners storage * @associates SpinButtonListener*/ private Vector spinButtonListeners = new Vector (3,3); /** Create new SpinButton. */ public SpinButton() { setBackground(SystemColor.control); setForeground(SystemColor.controlText); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { Dimension d = getSize(); boolean newDir = SPIN_UP; if (orientation) { if (evt.getX() <= ((d.width - 1) / 2)) newDir = SPIN_DOWN; else newDir = SPIN_UP; } else { if (evt.getY() <= ((d.height - 1) / 2)) newDir = SPIN_UP; else newDir = SPIN_DOWN; } if ((((newDir == SPIN_UP)&&(value >= maximum))||((newDir == SPIN_DOWN)&&(value <= minimum)))&&!boundsIgnored) return; switchRun(newDir); repaint(); } public void mouseReleased(MouseEvent evt) { boolean r = running; switchStop(); if (r) repaint(); } }); } /** * Setter method for foreground color. * * @param <CODE>Color color</COLOR> New foreground color. */ public void setForeground (Color color) { super.setForeground (color); repaint (); } /** Sets the new orientation. * @param aDir new value of orientation. * @see #orientation * @see #DEFAULT_ORIENTATION * @see #getOrientation */ public void setOrientation(boolean aDir) { orientation = aDir; switchStop(); repaint(); } /** Sets the new orientation of arows. * @param aDir new value of orientation of arows. * @see #orientation * @see #DEFAULT_ORIENTATION * @see #getOrientation */ public void setArrowsOrientation(boolean aDir) { arrowsOrientation = aDir; switchStop(); repaint(); } /** Gets the current orientation of SpinButton. * @return value of orientation. * @see #orientation * @see #DEFAULT_ORIENTATION * @see #setOrientation */ public boolean getOrientation() { return orientation; } /** Gets the current orientation of Arrows of SpinButton. * @return value of orientation of Arrows. * @see #orientation * @see #DEFAULT_ORIENTATION * @see #setOrientation */ public boolean getArrowsOrientation() { return arrowsOrientation; } /** Sets a minimum of the range of the SpinButton. If value * or maximum fall out of acceptable values they are adjusted. * @param aMin New minimum. * @see #getMinimum */ public void setMinimum(int aMin) { minimum = aMin; if (maximum < minimum) maximum = minimum; if (value < minimum) setValue(value); switchStop(); repaint(); } /** Gets the current minimum of the range of SpinButton. * @return Minimum. * @see #setMinimum */ public int getMinimum() { return minimum; } /** Sets a maximum of the range of the SpinButton. If value * or minimum fall out of acceptable values they are adjusted. * @param aMax New maximum. * @see #getMinimum */ public void setMaximum(int aMax) { maximum = aMax; if (maximum < minimum) minimum = maximum; if (value > maximum) setValue(value); switchStop(); repaint(); } /** Gets the current maximum of the range of SpinButton. * @return Maximum. * @see #setMaximum */ public int getMaximum() { return maximum; } /** Sets a new value of the SpinButton. If value is outside * the ranges it is set to nearest acceptable value. * @param aValue New value. * @see #getValue */ public void setValue(int aValue) { int oldValue = value; value = aValue; if (!boundsIgnored) { if (value < minimum) value = minimum; if (value > maximum) value = maximum; } if (value != oldValue) valueSupport.firePropertyChange("value", new Integer(oldValue), new Integer(value)); // NOI18N if ((getValue() == minimum) || (getValue() == maximum) || (oldValue == minimum) || (oldValue == maximum)) { repaint(); } } /** Gets the current value of the SpinButton. * @return Value. * @see #setValue */ public int getValue() { return value; } /** Sets a new step of the SpinButton. * @param aStep New step. * @see #getStep */ public void setStep(int aStep) { step = aStep; switchStop(); repaint(); } /** Gets the current step of the SpinButton. * @return Step. * @see #setStep */ public int getStep() { return step; } /** Sets new value of repeatDelay variable. * @param aDelay New delay. * @see #repeatDelay * @see #getDelay */ public void setDelay(int aDelay) { repeatDelay = aDelay; switchStop(); repaint(); } /** Gets the current value of repeatDelay variable. * @return Delay. * @see #repeatDelay * @see #setDelay */ public int getDelay() { return repeatDelay; } /** Sets new value of repeatRate variable. * @param aRate New rate. * @see #repeatRate * @see #getRate */ public void setRate(int aRate) { repeatRate = aRate; switchStop(); repaint(); } /** Gets the current value of rate variable. * @return Rate. * @see #repeatRate * @see #setRate */ public int getRate() { return repeatRate; } public boolean isBoundsIgnored () { return boundsIgnored; } public void setBoundsIgnored (boolean ignored) { boundsIgnored = ignored; } public boolean isRepeating () { return repeating; } public void setRepeating (boolean aRepeating) { repeating = aRepeating; } public void paint(Graphics g) { Dimension d = getSize(); int left = 0; int top = 0; int w = d.width - 1; int h = d.height - 1; g.setColor(getBackground()); g.fillRect(left,top,w,h); if (orientation) { w = w / 2; paintBorder(g, left, top, w, h, running && (runningDir == SPIN_DOWN), SPIN_DOWN); left += w + 1; w = d.width - 1 - left; paintBorder(g, left, top, w, h, running && (runningDir == SPIN_UP), SPIN_UP); } else { h = h / 2; paintBorder(g, left, top, w, h, running && (runningDir == SPIN_UP), SPIN_UP); top += h + 1; h = d.height - 1 - top; paintBorder(g, left, top, w, h, running && (runningDir == SPIN_DOWN), SPIN_DOWN); } } private void paintBorder(Graphics g, int x, int y, int w, int h, boolean isDown, boolean aDir) { g.setColor(Color.black); if (!isDown) { g.drawLine(x, y + h, x + w, y + h); g.drawLine(x + w, y, x + w, y + h); } else { g.drawLine(x, y, x + w, y); g.drawLine(x, y, x, y + h); x++; y++; } w--; h--; g.setColor(SystemColor.controlHighlight); g.draw3DRect(x, y, w, h, !isDown); paintArrow(g, x, y, w, h, aDir); } private void paintArrow(Graphics g, int x, int y, int w, int h, boolean aDir) { if ((w <= 0) || (h <= 0)) return; int wd = w / 4; int hd = h / 4; int[] xP = new int[3]; int[] yP = new int[3]; if (arrowsOrientation) { if (aDir == SPIN_UP) { xP[0] = x + wd; xP[2] = x + w - wd; } else { xP[0] = x + w - wd; xP[2] = x + wd; } xP[1] = xP[0]; yP[0] = y + hd; yP[1] = y + h - hd; yP[2] = y + h/2; } else { if (aDir == SPIN_UP) { yP[0] = y + h - hd; yP[2] = y + hd; } else { yP[0] = y + hd; yP[2] = y + h - hd; } yP[1] = yP[0]; xP[0] = x + wd; xP[1] = x + w - wd; xP[2] = x + w/2; } if ((((aDir == SPIN_UP)&&(value >= maximum))||((aDir == SPIN_DOWN)&&(value <= minimum))) && !boundsIgnored) { Color fg = getForeground(); Color bg = getBackground(); g.setColor(new Color((fg.getRed() + 2*bg.getRed())/3, (fg.getGreen() + 2*bg.getGreen())/3, (fg.getBlue() + 2*bg.getBlue())/3)); } else g.setColor(getForeground()); g.fillPolygon(xP, yP, 3); } protected synchronized void switchRun(boolean aDirect) { if (running) rt.finish = true; rt = new RepeatThread(); rt.start(); runningDir = aDirect; running = true; } public synchronized void switchStop() { if (rt == null) return; rt.finish = true; running = false; } public Dimension getMinimumSize() { return countSize(); } public Dimension getPreferredSize() { return countSize(); } private Dimension countSize() { int x = 11; int y = x; if (orientation) x = x + x; else y = y + y; return new Dimension(x, y); } public void addPropertyChangeListener(PropertyChangeListener l) { valueSupport.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { valueSupport.removePropertyChangeListener(l); } public void addSpinButtonListener (SpinButtonListener spinButtonListener) { spinButtonListeners.addElement (spinButtonListener); } public void removeSpinButtonListener (SpinButtonListener spinButtonListener) { spinButtonListeners.removeElement (spinButtonListener); } public void notifySpinButtonListenersAboutUpMove () { int i, k = spinButtonListeners.size (); for (i = 0; i < k; i ++) ((SpinButtonListener)spinButtonListeners.elementAt (i)).moveUp (); } public void notifySpinButtonListenersAboutDownMove () { int i, k = spinButtonListeners.size (); for (i = 0; i < k; i ++) ((SpinButtonListener)spinButtonListeners.elementAt (i)).moveDown (); } protected void repeatThreadNotify() { int old_val = getValue(); if (runningDir) { setValue(getValue() + step); if (value != old_val) notifySpinButtonListenersAboutUpMove (); } else { setValue(getValue() - step); if (value != old_val) notifySpinButtonListenersAboutDownMove (); } if ((getValue() == old_val) && !boundsIgnored) { switchStop(); repaint(); } } class RepeatThread extends Thread { boolean finish = false; public RepeatThread() { finish = false; } public void run() { repeatThreadNotify(); try { sleep(repeatDelay); } catch (InterruptedException e) { } if (!repeating) return; while (true) { if (finish) break; repeatThreadNotify(); if (finish) break; try { sleep(repeatRate); } catch (InterruptedException e) { } } } } } /* * Log * 6 Gandalf 1.5 1/12/00 Ian Formanek NOI18N * 5 Gandalf 1.4 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 4 Gandalf 1.3 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 3 Gandalf 1.2 4/19/99 Jesse Glick [JavaDoc] * 2 Gandalf 1.1 1/6/99 Ian Formanek Reflecting changes in * location of package "awt" * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ */